using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Reflector;
using Reflector.CodeModel;
using Reflector.Framework;
using Doubler.Templates;
using Doubler.Logging;
using Refly.Templates;

namespace ReflectorDouble
{
    public class MainView : UserControl, IServiceComponent
    {
        
#region Constructors

        public MainView()
        {
            this._Services = null;
            this.Dock = DockStyle.Fill;
            InitializeComponent();
        }

        public MainView(Type doublerType)
        {
            this._Services = null;
            this.Logger.LogEvent += new LogEventHandler(AppendToLogWindow);
            this.Dock = DockStyle.Fill;
            _DoublerType = doublerType;
            InitializeComponent();
        }
#endregion
        
#region Designer

        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainView));
            this.panel1 = new System.Windows.Forms.Panel();
            this.splitContainer1 = new System.Windows.Forms.SplitContainer();
            this.button1 = new System.Windows.Forms.Button();
            this.listView1 = new System.Windows.Forms.ListView();
            this.imageList1 = new System.Windows.Forms.ImageList(this.components);
            this.panel2 = new System.Windows.Forms.Panel();
            this.tabControl1 = new System.Windows.Forms.TabControl();
            this.tabPage1 = new System.Windows.Forms.TabPage();
            this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
            this.tabPage2 = new System.Windows.Forms.TabPage();
            this.textBoxLog = new System.Windows.Forms.TextBox();
            this.contextMenuStripLogWindow = new System.Windows.Forms.ContextMenuStrip(this.components);
            this.toolStripMenuItemClearLogWindow = new System.Windows.Forms.ToolStripMenuItem();
            this.toolStripMenuItemCopyLogWindowSelection = new System.Windows.Forms.ToolStripMenuItem();
            this.panel1.SuspendLayout();
            this.splitContainer1.Panel1.SuspendLayout();
            this.splitContainer1.Panel2.SuspendLayout();
            this.splitContainer1.SuspendLayout();
            this.panel2.SuspendLayout();
            this.tabControl1.SuspendLayout();
            this.tabPage1.SuspendLayout();
            this.tabPage2.SuspendLayout();
            this.contextMenuStripLogWindow.SuspendLayout();
            this.SuspendLayout();
            // 
            // panel1
            // 
            this.panel1.Controls.Add(this.splitContainer1);
            this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.panel1.Location = new System.Drawing.Point(0, 431);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(586, 100);
            this.panel1.TabIndex = 0;
            // 
            // splitContainer1
            // 
            this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.splitContainer1.Location = new System.Drawing.Point(0, 0);
            this.splitContainer1.Name = "splitContainer1";
            // 
            // splitContainer1.Panel1
            // 
            this.splitContainer1.Panel1.Controls.Add(this.button1);
            // 
            // splitContainer1.Panel2
            // 
            this.splitContainer1.Panel2.Controls.Add(this.listView1);
            this.splitContainer1.Size = new System.Drawing.Size(586, 100);
            this.splitContainer1.SplitterDistance = 444;
            this.splitContainer1.TabIndex = 1;
            // 
            // button1
            // 
            this.button1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.button1.Location = new System.Drawing.Point(0, 0);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(444, 100);
            this.button1.TabIndex = 0;
            this.button1.Text = "Generate";
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // listView1
            // 
            this.listView1.AllowDrop = true;
            this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.listView1.LargeImageList = this.imageList1;
            this.listView1.Location = new System.Drawing.Point(0, 0);
            this.listView1.Name = "listView1";
            this.listView1.Size = new System.Drawing.Size(138, 100);
            this.listView1.TabIndex = 0;
            this.listView1.UseCompatibleStateImageBehavior = false;
            this.listView1.View = System.Windows.Forms.View.Tile;
            this.listView1.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(this.OnQueryContinueDrag);
            this.listView1.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.OnItemDrag);
            // 
            // imageList1
            // 
            this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
            this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
            this.imageList1.Images.SetKeyName(0, "page_edit.png");
            // 
            // panel2
            // 
            this.panel2.Controls.Add(this.tabControl1);
            this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
            this.panel2.Location = new System.Drawing.Point(0, 0);
            this.panel2.Name = "panel2";
            this.panel2.Size = new System.Drawing.Size(586, 431);
            this.panel2.TabIndex = 1;
            // 
            // tabControl1
            // 
            this.tabControl1.Controls.Add(this.tabPage1);
            this.tabControl1.Controls.Add(this.tabPage2);
            this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.tabControl1.Location = new System.Drawing.Point(0, 0);
            this.tabControl1.Name = "tabControl1";
            this.tabControl1.SelectedIndex = 0;
            this.tabControl1.Size = new System.Drawing.Size(586, 431);
            this.tabControl1.TabIndex = 1;
            // 
            // tabPage1
            // 
            this.tabPage1.Controls.Add(this.propertyGrid1);
            this.tabPage1.Location = new System.Drawing.Point(4, 22);
            this.tabPage1.Name = "tabPage1";
            this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
            this.tabPage1.Size = new System.Drawing.Size(578, 405);
            this.tabPage1.TabIndex = 0;
            this.tabPage1.Text = "Settings";
            this.tabPage1.UseVisualStyleBackColor = true;
            // 
            // propertyGrid1
            // 
            this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.propertyGrid1.HelpVisible = false;
            this.propertyGrid1.Location = new System.Drawing.Point(3, 3);
            this.propertyGrid1.Name = "propertyGrid1";
            this.propertyGrid1.Size = new System.Drawing.Size(572, 399);
            this.propertyGrid1.TabIndex = 0;
            this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.onPropertyValueChange);
            // 
            // tabPage2
            // 
            this.tabPage2.Controls.Add(this.textBoxLog);
            this.tabPage2.Location = new System.Drawing.Point(4, 22);
            this.tabPage2.Name = "tabPage2";
            this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
            this.tabPage2.Size = new System.Drawing.Size(578, 405);
            this.tabPage2.TabIndex = 1;
            this.tabPage2.Text = "Log";
            this.tabPage2.UseVisualStyleBackColor = true;
            // 
            // textBoxLog
            // 
            this.textBoxLog.AcceptsReturn = true;
            this.textBoxLog.AcceptsTab = true;
            this.textBoxLog.BackColor = System.Drawing.SystemColors.Window;
            this.textBoxLog.ContextMenuStrip = this.contextMenuStripLogWindow;
            this.textBoxLog.Dock = System.Windows.Forms.DockStyle.Fill;
            this.textBoxLog.Location = new System.Drawing.Point(3, 3);
            this.textBoxLog.Multiline = true;
            this.textBoxLog.Name = "textBoxLog";
            this.textBoxLog.ReadOnly = true;
            this.textBoxLog.Size = new System.Drawing.Size(572, 399);
            this.textBoxLog.TabIndex = 0;
            // 
            // contextMenuStripLogWindow
            // 
            this.contextMenuStripLogWindow.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.toolStripMenuItemClearLogWindow,
            this.toolStripMenuItemCopyLogWindowSelection});
            this.contextMenuStripLogWindow.Name = "contextMenuStripLogWindow";
            this.contextMenuStripLogWindow.Size = new System.Drawing.Size(153, 70);
            // 
            // toolStripMenuItemClearLogWindow
            // 
            this.toolStripMenuItemClearLogWindow.Name = "toolStripMenuItemClearLogWindow";
            this.toolStripMenuItemClearLogWindow.Size = new System.Drawing.Size(152, 22);
            this.toolStripMenuItemClearLogWindow.Text = "Clear";
            this.toolStripMenuItemClearLogWindow.Click += new System.EventHandler(this.ClearLogWindow);
            // 
            // toolStripMenuItemCopyLogWindowSelection
            // 
            this.toolStripMenuItemCopyLogWindowSelection.Name = "toolStripMenuItemCopyLogWindowSelection";
            this.toolStripMenuItemCopyLogWindowSelection.Size = new System.Drawing.Size(152, 22);
            this.toolStripMenuItemCopyLogWindowSelection.Text = "Copy";
            this.toolStripMenuItemCopyLogWindowSelection.Click += new System.EventHandler(this.CopyFromLogWindow);
            // 
            // MainView
            // 
            this.AllowDrop = true;
            this.Controls.Add(this.panel2);
            this.Controls.Add(this.panel1);
            this.Name = "MainView";
            this.Size = new System.Drawing.Size(586, 531);
            this.panel1.ResumeLayout(false);
            this.splitContainer1.Panel1.ResumeLayout(false);
            this.splitContainer1.Panel2.ResumeLayout(false);
            this.splitContainer1.ResumeLayout(false);
            this.panel2.ResumeLayout(false);
            this.tabControl1.ResumeLayout(false);
            this.tabPage1.ResumeLayout(false);
            this.tabPage2.ResumeLayout(false);
            this.tabPage2.PerformLayout();
            this.contextMenuStripLogWindow.ResumeLayout(false);
            this.ResumeLayout(false);

        }

        #endregion

        private Panel panel1;
        private Panel panel2;
        private Button button1;
        private PropertyGrid propertyGrid1;
        private SplitContainer splitContainer1;
        private ListView listView1;
        private ImageList imageList1;
#endregion
        
#region Fields

        private TemplateBase _Template;
        private Type _DoublerType;
        private DataObject _DragData;
        private LoggerBase _Logger;

#endregion
        
#region Properties

        public LoggerBase Logger
        {
            get
            {
                if (_Logger == null)
                    _Logger = LogClassFactory.Logger;
                return _Logger;
            }
            set
            {
                _Logger = value;
            }
        }

        public TemplateBase Template
        {
            get
            {
                return _Template;
            }
            set
            {
                _Template = value;
            }
        }

        public Type DoublerType
        {
            get
            {
                return _DoublerType;
            }
            set
            {
                _DoublerType = value;
            }
        }
   
        public DataObject DragData
        {
            get
            {
                return _DragData;
            }
            set
            {
                _DragData = value;
            }
        }

#endregion
        
#region Item Selection Change

        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);
            if (base.Parent != null)
            {
                this.PopulatePropertyGrid();
                this.PopulateExplorerView();
                this.ClearLogWindow();
            }
        }

        public void activeItem_Changed(object sender, EventArgs args)
        {
            if (base.Parent != null)
            {
                this.PopulatePropertyGrid();
                this.PopulateExplorerView();
                this.ClearLogWindow();
            }
        }

#endregion
        
#region PropertyGrid

        private void PopulatePropertyGrid()
        {
            if (this.Services.ActiveItem is IAssembly)
            {
                IAssembly assembly = this.Services.ActiveAssembly;
                if (assembly != null)
                {
                    try
                    {
                        object[] Args = new object[4] { Refly.CodeDom.CodeLanguage.Vb, @"C:\Temp", assembly, this.Services };
                        this.Template = (ManyTemplateBase)Activator.CreateInstance(this.DoublerType, Args);
                        this.propertyGrid1.Name = assembly.Name;
                        this.propertyGrid1.SelectedObject = this.Template;
                    }
                    catch (Exception ex)
                    {
                        this.propertyGrid1.SelectedObject = ex;
                    }
                }
            }
            else
            {
                ITypeDeclaration declaration1 = this.Services.ActiveTypeDeclaration;
                if (declaration1 != null)
                {
                    try
                    {
                        object[] Args = new object[4] { Refly.CodeDom.CodeLanguage.Vb, @"C:\Temp", declaration1, this.Services };
                        this.Template = (TemplateBase)Activator.CreateInstance(this.DoublerType, Args);
                        this.propertyGrid1.Name = declaration1.Name;
                        this.propertyGrid1.SelectedObject = this.Template;
                    }
                    catch (Exception ex)
                    {
                        this.propertyGrid1.SelectedObject = ex;
                    }
                }
            }
        }

#endregion
        
#region Generate Button

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                this.ClearLogWindow();
                this.Template.Generate();
            }
            catch (Exception ex)
            {
                this.propertyGrid1.SelectedObject = ex;
            }
        }

#endregion

#region IServiceComponent Members

        private ReflectorServices _Services;

        public ReflectorServices Services
        {
            get
            {
                return _Services;
            }
            set
            {
                if (_Services != null)
                {
                    //AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(this.AssemblyResolve);
                    this.Services.AssemblyBrowser.ActiveItemChanged -= new EventHandler(this.activeItem_Changed);
                }
                _Services = value;
                if (_Services != null)
                {
                    //AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(this.AssemblyResolve);
                    this.Services.AssemblyBrowser.ActiveItemChanged += new EventHandler(this.activeItem_Changed);
                }
            }
        }
        
#endregion
        
#region Reflection Helpers

        //private Assembly AssemblyResolve(object sender, ResolveEventArgs args)
        //{
        //    char[] Separators = new char[1] { ',' };
        //    string AsmName = args.Name.Split(Separators)[0];
        //    foreach (string Directory in Doubler.MetaHelper.HintDirectories)
        //    {
        //        string AsmPath = Path.Combine(Directory, string.Format("{0}.dll", AsmName));
        //        if (System.IO.File.Exists(AsmPath))
        //        {
        //            return Assembly.LoadFrom(AsmPath);
        //        }
        //        AsmPath = Path.Combine(Directory, string.Format("{0}.exe", AsmName));
        //        if (System.IO.File.Exists(AsmPath))
        //        {
        //            return Assembly.LoadFrom(AsmPath);
        //        }
        //    }
        //    return null;
        //}

#endregion
       
#region Populate List View

        private void onPropertyValueChange(object s, PropertyValueChangedEventArgs e)
        {
            this.PopulateExplorerView();
        }

        private void PopulateExplorerView()
        {
            this.listView1.Items.Clear();
            ListViewItem Item = new ListViewItem(this.Template.FileName, 0);
            this.listView1.Items.Add(Item);
        }

#endregion
        
#region Drag and Drop
        
        private void DoDragLeave()
        {
            String[] fileNames;
            DragData = new DataObject();
            fileNames = new String[1] { Regex.Replace(this.Template.OutputFilePath, @"/", @"\\") };
            DragData.SetData(DataFormats.FileDrop, fileNames);
            DragData.SetData(ShellClipboardFormats.CFSTR_PREFERREDDROPEFFECT, DragDropEffects.Copy);
            DragData.SetData(ShellClipboardFormats.CFSTR_INDRAGLOOP, 1);
            listView1.DoDragDrop(DragData, DragDropEffects.Copy);
            DragData = null;
        }


        private void OnItemDrag(object sender, ItemDragEventArgs e)
        {
            this.DoDragLeave();
        }

        private void OnQueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            //ESC pressed
            if (e.EscapePressed)
            {
                e.Action = DragAction.Cancel;
                return;
            }
            //Drop!
            if (e.KeyState == 0)
            {
                DragData.SetData(ShellClipboardFormats.CFSTR_INDRAGLOOP, 0);
                e.Action = DragAction.Drop;
                return;
            }
            e.Action = DragAction.Continue;
        }

#endregion

        private TabControl tabControl1;
        private TabPage tabPage1;
        private TabPage tabPage2;

        private void AppendToLogWindow(String message)
        {
            String Entry = string.Format("{0}{1}{2} {3}:{4}{5}",
                Environment.NewLine,
                Environment.NewLine,
                System.DateTime.Now.ToShortDateString(),
                System.DateTime.Now.ToShortTimeString(),
                Environment.NewLine,
                message);
            
            int NewLength = this.textBoxLog.Text.Length + Entry.Length;
            if (NewLength > this.textBoxLog.MaxLength)
            {
                NewLength -= this.textBoxLog.MaxLength;
                try
                {
                    this.textBoxLog.Text = this.textBoxLog.Text.Remove(1, NewLength);
                }
                catch
                {
                }
            }

            this.textBoxLog.AppendText(Entry);
            this.textBoxLog.ScrollToCaret();
        }

        private TextBox textBoxLog;
        private ContextMenuStrip contextMenuStripLogWindow;
        private ToolStripMenuItem toolStripMenuItemClearLogWindow;
        private ToolStripMenuItem toolStripMenuItemCopyLogWindowSelection;

        private void ClearLogWindow(object sender, EventArgs e)
        {
            this.ClearLogWindow();
        }

        private void ClearLogWindow()
        {
            this.textBoxLog.Clear();
        }

        private void CopyFromLogWindow(object sender, EventArgs e)
        {
            if (this.textBoxLog.SelectionLength > 0)
            {
                Clipboard.SetText(this.textBoxLog.SelectedText);
            }
            else
            {
                Clipboard.SetText(this.textBoxLog.Text);
            }
        }

    }

    
#region Shell Clipboard Formats

    public class ShellClipboardFormats
    {
        public const string CFSTR_SHELLIDLIST = "Shell IDList Array";
        public const string CFSTR_SHELLIDLISTOFFSET = "Shell Object Offsets";
        public const string CFSTR_NETRESOURCES = "Net Resource";
        public const string CFSTR_FILEDESCRIPTORA = "FileGroupDescriptor";
        public const string CFSTR_FILEDESCRIPTORW = "FileGroupDescriptorW";
        public const string CFSTR_FILECONTENTS = "FileContents";
        public const string CFSTR_FILENAMEA = "FileName";
        public const string CFSTR_FILENAMEW = "FileNameW";
        public const string CFSTR_PRINTERGROUP = "PrinterFreindlyName";
        public const string CFSTR_FILENAMEMAPA = "FileNameMap";
        public const string CFSTR_FILENAMEMAPW = "FileNameMapW";
        public const string CFSTR_SHELLURL = "UniformResourceLocator";
        public const string CFSTR_INETURLA = CFSTR_SHELLURL;
        public const string CFSTR_INETURLW = "UniformResourceLocatorW";
        public const string CFSTR_PREFERREDDROPEFFECT = "Preferred DropEffect";
        public const string CFSTR_PERFORMEDDROPEFFECT = "Performed DropEffect";
        public const string CFSTR_PASTESUCCEEDED = "Paste Succeeded";
        public const string CFSTR_INDRAGLOOP = "InShellDragLoop";
        public const string CFSTR_DRAGCONTEXT = "DragContext";
        public const string CFSTR_MOUNTEDVOLUME = "MountedVolume";
        public const string CFSTR_PERSISTEDDATAOBJECT = "PersistedDataObject";
        public const string CFSTR_TARGETCLSID = "TargetCLSID";
        public const string CFSTR_LOGICALPERFORMEDDROPEFFECT = "Logical Performed DropEffect";
        public const string CFSTR_AUTOPLAY_SHELLIDLISTS = "Autoplay Enumerated IDList Array";
    }

#endregion

}
